BufferedReader
BufferedReader 缓冲流中提供了对纯文本数据进行按行读取处理的方法 readLine, 方法返回的是读取到的字符串,如果没有读取到则返回 null。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| package com.itguigu.com;
import java.io.BufferedReader;
import java.io.FileReader; import java.io.IOException;
public class TestBufferReader { public static void main(String[] args) throws IOException { FileReader fileReader = new FileReader("resources/text.txt"); BufferedReader bufferedReader = new BufferedReader(fileReader); String line; while ((line = bufferedReader.readLine())!=null) { System.out.println(line); } } }
|
DataOoutputStream
可以将基本的 Java 数据类型写入输出流 DataInputStream 中。
Java 基本数据类型:8种
基本的 Java 数据类型:8 种 + String
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| import java.io.IOException;
import org.junit.Test;
public class TestDataOutputStream { @Test public void save() throws IOException { String name = "张三"; int age = 1000; char gender = '男'; double salary = 100.1; DataOutputStream dataOutputStream = new DataOutputStream(new FileOutputStream("resources/data.dat")); dataOutputStream.writeUTF(name); dataOutputStream.writeInt(age); dataOutputStream.writeChar(gender); dataOutputStream.writeDouble(salary); dataOutputStream.close(); } }
|
可以从底层输入流中读取基本 Java 数据类型的数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| package com.itguigu.com;
import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException;
import org.junit.Test;
public class TestDataOutputStream { @Test public void read() throws IOException { DataInputStream dataInputStream = new DataInputStream(new FileInputStream("resources/data.dat")); String name = dataInputStream.readUTF(); int readInt = dataInputStream.readInt(); char readChar = dataInputStream.readChar(); double readDouble = dataInputStream.readDouble(); System.out.println(name); System.out.println(readInt); System.out.println(readChar); System.out.println(readDouble); dataInputStream.close(); } }
|
ObjectOutputStream
输出对象,可以称为序列化
1 2 3 4 5 6 7 8
| @Test public void save() throws IOException { Employee employee = new Employee(1, "zhangsan", 100001); ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("resources/employee.dat")); objectOutputStream.writeObject(employee); objectOutputStream.close(); }
|
读取对象,也可以称为反序列化
1 2 3 4 5 6 7 8
| @Test public void read() throws IOException, ClassNotFoundException { ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("resources/employee.dat")); System.out.println(objectInputStream.readObject()); objectInputStream.close(); }
|
完整代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
| package com.itguigu.com;
import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable;
import org.junit.Test;
public class TestObjectIO { @Test public void save() throws IOException { Employee employee = new Employee(1, "zhangsan", 100001); ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("resources/employee.dat")); objectOutputStream.writeObject(employee); objectOutputStream.close(); } @Test public void read() throws IOException, ClassNotFoundException { ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("resources/employee.dat")); System.out.println(objectInputStream.readObject()); objectInputStream.close(); } }
class Employee implements Serializable{ private int id; private String name; private double salary; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public double getSalary() { return salary; } public void setSalary(double salary) { this.salary = salary; } public Employee(int id, String name, double salary) { super(); this.id = id; this.name = name; this.salary = salary; } public Employee() { super(); } @Override public String toString() { return "Employee [id=" + id + ", name=" + name + ", salary=" + salary + "]"; } }
|
在实现 Serializable 接口时,最好需要加上 serialVersionID(序列化版本 ID),如果不加,那么只要类重新编译,原来序列化的数据就无法反序列化了,因为每次编译都会自动随机产生一个 serialVersionID。如果加了,那么就算类重新编译,serialVersionID 的值不变,原来序列化的数据仍然可以反序列化。
自定义异常中的 serialVersionUID
- 继承 Throwable 或它的子类
- 建议保留两个构造器
- 增加序列化版本 ID
- 自定义异常对象只能使用 throw 抛出
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| package com.itguigu.com;
public class MyException extends Exception{ private static final long serialVersionUID = 7558865975137180878L;
public MyException() { super(); }
public MyException(String message) { super(message); } }
|
Serializable
在实现 Serializable 接口时,最好需要加上 serialVersionID(序列化版本 ID)。
如果一个对象中的某些属性不想被序列化,那么只需要在该属性的参数类型前面加上 transient 即可。
一个类的静态变量是不会序列化的,即序列化前后值不变。因为静态变量不是属于某个对象的,是所有对象共享的。而序列化对象保存的是对象的状态信息,是每个对象独立的信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
| package com.itguigu.com;
import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable;
import org.junit.Test;
public class TestObjectIO { @Test public void save() throws IOException { Employee employee = new Employee(1, "zhangsan", 100001); ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("resources/employee.dat")); objectOutputStream.writeObject(employee); objectOutputStream.close(); } @Test public void read() throws IOException, ClassNotFoundException { ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("resources/employee.dat")); System.out.println(objectInputStream.readObject()); objectInputStream.close(); } }
class Employee implements Serializable{ private static final long serialVersionUID = 4356894757096033197L; private int id; private String name; private transient double salary; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public double getSalary() { return salary; } public void setSalary(double salary) { this.salary = salary; } public Employee(int id, String name, double salary) { super(); this.id = id; this.name = name; this.salary = salary; } public Employee() { super(); } @Override public String toString() { return "Employee [id=" + id + ", name=" + name + ", salary=" + salary + "]"; } }
|
Externalizable
除了实现 Serializable 接口可以实现序列化以外,Externalizable 接口也可以实现。java.io.Externalizable 是继承自 Serializable 接口的。但是实现 Externalizable 接口后必须重写两个抽象方法,writeExternal 和 readExternal。Externalizable 不同于 Serializable,Externalizable 可以自定义序列化和反序列化的属性,顺序等,而 Serializable 序列化的顺序是默认的,且 static 和 transient 是不能序列化的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
| package com.itguigu.com;
import java.io.Externalizable; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectInputStream; import java.io.ObjectOutput; import java.io.ObjectOutputStream;
import org.junit.Test;
public class TestExternalizable { @Test public void save() throws IOException { Student23 student23 = new Student23("zhangsan", 23); student23.setSalary(890890.1); ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("resources/obj.dat")); objectOutputStream.writeObject(student23); objectOutputStream.close(); } @Test public void read() throws IOException, ClassNotFoundException { ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("resources/obj.dat")); System.out.println(objectInputStream.readObject()); objectInputStream.close(); } }
class Student23 implements Externalizable{ private String name; private transient int age; private static double salary=30000; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public static double getSalary() { return salary; } public static void setSalary(double salary) { Student23.salary = salary; } @Override public String toString() { return name + "," + age + "," + salary; } public Student23(String name, int age) { super(); this.name = name; this.age = age; } public Student23() { super(); } @Override public void writeExternal(ObjectOutput out) throws IOException { out.writeUTF(name); out.writeInt(age); out.writeDouble(salary); } @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { name = in.readUTF(); age = in.readInt(); salary = in.readDouble(); } }
|
System 中的 IO 流
- System.in, 类型为 InputStream
- System.out, 类型为 PrintStream
- System.err, 类型为 PrintStream
进程和线程
进程是操作系统分配资源的最小单位,线程是 CPU 调度资源的最小单位。多个线程之间存在内存共享,共享同一个进程的资源。因为 CPU 给每个线程分配到的时间非常短,所以用户没有感觉,就如同时运行一样。
JVM运行时内存:方法区,堆,栈(虚拟机栈,本地方法栈),程序计数器。其中堆内存和方法区的内存是共享的,栈和程序计数器是每个线程独立的。
堆:存放对象。即实例是线程共享的。
方法区:存放类信息,常量,静态相关信息等。即常量,静态变量是线程共享的。
栈:存放局部变量。即局部变量是每个线程都是独立的。
Thread
实现多线程的方法之一就是继承 java.lang.Thread 类,并且重写 run 方法。
步骤:
- 声明线程类,继承 Thread 类
- 重写 run 方法
- 创建线程对象
- 启动线程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| package com.itguigu.com;
public class TestThread { public static void main(String[] args) { MyThread myThread = new MyThread(); myThread.start(); for (int i = 1; i < 100; i+=2) { System.out.println("奇数:" + i); } } }
class MyThread extends Thread{ @Override public void run() { for (int i = 2; i < 100; i+=2) { System.out.println("偶数:" + i); } } }
|
常见方法
- 构造器。共有三种构造器,分别是 Thread(),Thread(Runnable target),Thread(Runnable target, String name)
- getName()/setName(String name),获取和设置线程名称。默认线程名称是 Thread-编号
- Thread.currentThread(),获取当前线程对象。是静态方法
- getPriority,setPriority(int newPriority),获取和设置线程优先级。Java 中线程优先级一共有 10 个等级,从1到10,数字越大则代表等级越高,Thread 类中预定义了三个最基本的优先级,MIN_PRIORITY:1, NORM_PRIORITY:5, MAX_PRIORITY: 10。如果优先级不在 1-10 的范围内,则会抛出异常。
- Thread.sleep(int xx),线程睡眠。是静态方法
- join(), 线程加塞,或者插队。需要等到加塞进来的线程执行结束后,才能继续之前的线程。
- Thread.yield。暂停当前线程,让出本次 CPU 的资源。是静态方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| package com.itguigu.com;
public class TestThreadMethod { public static void main(String[] args) throws InterruptedException { CusThread cusThread = new CusThread(); System.out.println(cusThread.getName()); cusThread.setPriority(5); cusThread.start(); CusThread cusThread2 = new CusThread(); cusThread2.setName("new Name"); System.out.println(cusThread2.getName()); cusThread2.start(); for (int i = 0; i < 10; i++) { if (i==5) { cusThread.join(); } System.out.println(Thread.currentThread().getName() + ": " + i); } } }
class CusThread extends Thread{ @Override public void run() { for (int i = 0; i < 5; i++) { try { Thread.sleep(1000); System.out.println(getName() + ":" + i); } catch (InterruptedException e) { e.printStackTrace(); } } } }
|
Runnable
实现多线程还可以实现 java.lang.Runnable 接口,并重写 run 方法。Runnable 中没有 start 方法,只有 Thread 中有 start 方法,所以必须要 Thread 类的对象才能启动多线程。
步骤:
- 声明线程类,实现 Runnable 接口
- 重写 run 方法
- 创建线程对象
- 创建 Thread 对象
- 启动线程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| package com.itguigu.com;
public class testRunnable { public static void main(String[] args) { myThread2 myThread2 = new myThread2(); Thread thread = new Thread(myThread2); thread.start(); for (int i = 1; i < 100; i+=2) { System.out.println("奇数:" + i); } } }
class myThread2 implements Runnable{
@Override public void run() { for (int i = 2; i < 100; i+=2) { System.out.println("偶数:" + i); } } }
|